/*
 * Copyright 2006-2023 ahtelit.com, All Rights Reserved.
 */

package com.telit.firecommand.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.telit.common.dto.DistrictDTO;
import com.telit.common.entity.PageData;
import com.telit.firecommand.dao.GeoXzqhCunDao;
import com.telit.firecommand.dao.IotDataDAO;
import com.telit.firecommand.dao.IotDeviceDAO;
import com.telit.firecommand.dto.DistrictCountDTO;
import com.telit.firecommand.dto.GeoCunDTO;
import com.telit.firecommand.entity.IotData;
import com.telit.firecommand.entity.IotDevice;
import com.telit.firecommand.model.iot.IotDeviceListModel;
import com.telit.firecommand.model.iot.QryDevicesDataRequest;
import com.telit.firecommand.model.iot.QryDevicesListRequest;
import com.telit.firecommand.service.DistrictService;
import com.telit.firecommand.service.IotService;
import com.telit.firecommand.util.IotUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * IotServiceImpl
 *
 * @author yuezhuang
 * @since 2023-04-27
 */
@Transactional
@RequiredArgsConstructor
@Slf4j
@Service
public class IotServiceImpl implements IotService {

    private final IotDeviceDAO iotDeviceDAO;

    private final IotDataDAO iotDataDAO;

    private final GeoXzqhCunDao geoXzqhCunDao;

    private final DistrictService districtService;

    /**
     * 查询第三方IOT设备列表
     */
    @Override
    public PageData<List<IotDeviceListModel>> qryOutDeviceList(QryDevicesListRequest qryDevicesListRequest) {
        PageData<List<IotDeviceListModel>> pageData = IotUtil.devices(qryDevicesListRequest);
        List<IotDeviceListModel> deviceListModels = pageData.getDatas();
        List<String> snList = deviceListModels.stream().map(IotDeviceListModel::getSn).collect(Collectors.toList());

        LambdaQueryWrapper<IotDevice> iotDeviceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        iotDeviceLambdaQueryWrapper.in(IotDevice::getSn, snList);
        List<IotDevice> iotDevices = iotDeviceDAO.selectList(iotDeviceLambdaQueryWrapper);
        //数据库存在的数据
        Map<String, IotDevice> existDevices = iotDevices.stream().collect(
                Collectors.toMap(IotDevice::getSn, Function.identity(), (key1, key2) -> key2));

        deviceListModels.forEach(iotDeviceListModel -> {
            IotDevice iotDevice = existDevices.get(iotDeviceListModel.getSn());
            if (iotDevice == null) {
//                IotDeviceMeteorologyModel meteorology = IotUtil.meteorology(iotDeviceListModel.getSn());
                GeoCunDTO geoCunDTO = geoXzqhCunDao.getDistrictByPoint(
                        String.valueOf(iotDeviceListModel.getDeployment().getLnglat().get(0)),
                        String.valueOf(iotDeviceListModel.getDeployment().getLnglat().get(1)));
                if (geoCunDTO == null) {
                    log.error("当前设备经纬度解析失败：{}", iotDeviceListModel);
                    return;
                }
                iotDevice = IotDevice.builder()
                        .mockId(iotDeviceListModel.getId())
                        .sn(iotDeviceListModel.getSn())
                        .name(iotDeviceListModel.getName())
                        .type(iotDeviceListModel.getDeviceType())
                        .model(iotDeviceListModel.getModel())
                        .category(iotDeviceListModel.getCategory())
                        .categoryName(iotDeviceListModel.getCategoryName())
                        .networkStatus(iotDeviceListModel.isNetworkStatus())
                        .status(iotDeviceListModel.getStatus())
                        .createdTime(iotDeviceListModel.getCreatedTime())
                        .deployedTime(iotDeviceListModel.getDeployedTime())
                        .location(iotDeviceListModel.getDeployment().getLocation())
                        .longitude(String.valueOf(iotDeviceListModel.getDeployment().getLnglat().get(0)))
                        .latitude(String.valueOf(iotDeviceListModel.getDeployment().getLnglat().get(1)))
                        .imageUrl(iotDeviceListModel.getMainPicture())
                        .skuName(iotDeviceListModel.getSkuName())
                        .alarmState(null)
                        .faultState(null)
                        .districtCode(geoCunDTO.getXian())
                        .districtName(geoCunDTO.getXianName())
                        .build();
                iotDeviceDAO.insert(iotDevice);
            }
        });

        return pageData;
    }

    /**
     * 查询数据库IOT设备列表
     */
    @Override
    public PageData<List<IotDevice>> qryDeviceList(QryDevicesListRequest qryDevicesListRequest) {
        LambdaQueryWrapper<IotDevice> iotDeviceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        iotDeviceLambdaQueryWrapper.likeRight(IotDevice::getDistrictCode, qryDevicesListRequest.getDistrictCode());
        Page<IotDevice> iotDevicePage = iotDeviceDAO.selectPage(
                new Page<>(qryDevicesListRequest.getPage(), qryDevicesListRequest.getSize()),
                iotDeviceLambdaQueryWrapper);
        return PageData.<List<IotDevice>>builder()
                .count((int) iotDevicePage.getTotal())
                .size(qryDevicesListRequest.getSize())
                .current(qryDevicesListRequest.getPage())
                .datas(iotDevicePage.getRecords())
                .build();
    }

    /**
     * 查询数据库IOT设备数据列表
     */
    @Override
    public PageData<List<IotData>> qryDeviceDataList(QryDevicesDataRequest qryDevicesDataRequest) {
        LambdaQueryWrapper<IotData> iotDataLambdaQueryWrapper = new LambdaQueryWrapper<>();
        iotDataLambdaQueryWrapper.eq(IotData::getSn, qryDevicesDataRequest.getSn());
        iotDataLambdaQueryWrapper.orderByDesc(IotData::getCreatedAt);
        if (StrUtil.isNotEmpty(qryDevicesDataRequest.getMessageType())) {
            iotDataLambdaQueryWrapper.eq(IotData::getMessageType, qryDevicesDataRequest.getMessageType());
        }
        Page<IotData> iotDataPage = iotDataDAO.selectPage(
                new Page<>(qryDevicesDataRequest.getPage(), qryDevicesDataRequest.getSize()),
                iotDataLambdaQueryWrapper);
        return PageData.<List<IotData>>builder()
                .count((int) iotDataPage.getTotal())
                .size(qryDevicesDataRequest.getSize())
                .current(qryDevicesDataRequest.getPage())
                .datas(iotDataPage.getRecords())
                .build();
    }

    /**
     * 查询数据库IOT设备详情
     */
    @Override
    public IotDevice qryDeviceDetail(Long id, String sn) {
        LambdaQueryWrapper<IotDevice> iotDeviceLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (id != null) {
            iotDeviceLambdaQueryWrapper.eq(IotDevice::getId, id);
        }
        if (StrUtil.isNotEmpty(sn)) {
            iotDeviceLambdaQueryWrapper.eq(IotDevice::getSn, sn);
        }
        IotDevice iotDevice = iotDeviceDAO.selectOne(iotDeviceLambdaQueryWrapper);
        QryDevicesDataRequest qryDevicesDataRequest = QryDevicesDataRequest.builder()
                .page(1)
                .size(1)
                .sn(iotDevice.getSn())
                .messageType("data")
                .build();
        PageData<List<IotData>> listPageData = this.qryDeviceDataList(qryDevicesDataRequest);
        iotDevice.setIotDataList(listPageData.getDatas());
        return iotDevice;
    }

    /**
     * 查询数量
     */
    @Override
    public DistrictCountDTO count(String districtCode, Boolean networkStatus, String name) {
        long totalCount = iotDeviceDAO.count(districtCode, true, null, name);
        long onlineCount = iotDeviceDAO.count(districtCode, true, true, name);
        return DistrictCountDTO.builder()
                .count((int) totalCount)
                .offlineCount((int) (totalCount - onlineCount))
                .onlineCount((int) onlineCount)
                .build();
    }

    /**
     * 查询树形结构
     */
    @Override
    public DistrictCountDTO treeDistrict(String districtCode, Boolean networkStatus, String name) {
        //当前行政区划信息
        DistrictDTO current = districtService.qryDistrictInfo(districtCode);
        //当前行政区划下护林员数量（包含子行政区划）
        long currentCount = iotDeviceDAO.count(districtCode, true, networkStatus, name);
        //当前行政区划下列表（不包含子行政区划）
        List<IotDevice> iotDeviceList = new ArrayList<>();
        if (currentCount > 0) {
            iotDeviceList = iotDeviceDAO.selectByCondition(districtCode, false, networkStatus, name, Integer.MAX_VALUE,
                    0);
        }
        //构建返回DTO
        DistrictCountDTO districtCountDTO = DistrictCountDTO.builder()
                .id(current.getId())
                .name(current.getName())
                .code(current.getCode())
                .parentCode(current.getParentCode())
                .rank(current.getRank())
                .count((int) currentCount)
                .iotDeviceList(iotDeviceList)
                .build();
        List<DistrictCountDTO> countChildren = new ArrayList<>();
        //子类行政区划集合
        List<DistrictDTO> children = new ArrayList<>();
        if (districtCode.length() < 12) {
            children = districtService.qryListByParentCode(districtCode, null);
        }
        children.forEach(districtDTO -> {
            long childCount = iotDeviceDAO.count(districtDTO.getCode(), true, networkStatus, name);
            List<IotDevice> childList = new ArrayList<>();
            if (childCount > 0) {
                childList = iotDeviceDAO.selectByCondition(districtDTO.getCode(), false, networkStatus, name,
                        Integer.MAX_VALUE, 0);
            }
            DistrictCountDTO countDTO = DistrictCountDTO.builder()
                    .id(districtDTO.getId())
                    .name(districtDTO.getName())
                    .code(districtDTO.getCode())
                    .parentCode(districtDTO.getParentCode())
                    .rank(districtDTO.getRank())
                    .count((int) childCount)
                    .iotDeviceList(childList)
                    .build();
            countChildren.add(countDTO);
        });
        districtCountDTO.setChildren(countChildren);
        return districtCountDTO;
    }

}
